<?php

namespace mpend\models;

use Yii;
use yii\db\Exception;
use common\models\open\OpenClient;
use common\models\open\OpenToken;

/**
 * APP接口访问授权接口
 * Authorization
 * 
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class AuthorizationForm extends \common\base\Model {

    /**
     * @var string 授权应用ID
     */
    public $appid;

    /**
     * @var string 时间戳
     */
    public $timestamp;

    /**
     * @var string 随机字符串
     */
    public $nonce;

    /**
     * @var string 签名字符串
     */
    public $sign;

    /**
     * @var object 客户端
     */
    private $_client = null;

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['appid', 'nonce', 'sign', 'timestamp'], 'required'],
            [['timestamp'], 'integer'],
            [['nonce'], 'string', 'max' => 32],
            ['appid', 'validateAppId'],
            ['sign', 'validateSignature'],
        ];
    }

    /**
     * 验证APPID是否为授权应用
     * @param string $attribute `appid`
     */
    public function validateAppId($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        if (!$this->getClient()) {
            $this->addError($attribute, '未授权的应用ID');
        }
    }

    /**
     * 校验请求的签名
     * @param string $attribute `sign`
     */
    public function validateSignature($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $validated = Yii::$app->security->validateSignature($this->attributes, $this->getClient()->secret);
        if ($validated !== true) {
            $tips = '签名校验失败';
            if (YII_DEBUG) {
                $tips .= $validated;
            }
            $this->addError($attribute, $tips);
        }
    }

    /**
     * 获取APP授权应用客户端
     * @return \common\models\app\AppClient|null
     */
    protected function getClient() {
        if ($this->_client === null) {
            $this->_client = OpenClient::findByAppId($this->appid);
        }
        return $this->_client;
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels() {
        return [
            'appid' => 'AppID',
            'nonce' => '随机串',
            'timestamp' => '时间戳',
            'sign' => '签名',
        ];
    }

    /**
     * 认证授权操作
     * @inheritdoc
     */
    public function authorize() {
        if (!$this->validate()) {
            return $this->dumpError('请求数据校验失败');
        }
        $token = $this->executeTransaction(__FUNCTION__);
        $data = [
            'access_token' => $token->access_token,
            'expired_at' => $token->expired_at,
        ];
        return $data;
    }

    /**
     * 数据保存
     * @inheritdoc
     */
    protected function transactAuthorize() {
        $token = OpenToken::findOrNew([
            'client_id' => $this->client->id,
        ]);
        $token->generateAccessToken();
        if (!$token->save()) {
            throw new Exception('Token生成失败', $token->errorMsg);
        }
        return $token;
    }

}
